/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.bah.tract.security;

import java.io.IOException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.util.Map;
import java.util.prefs.Preferences;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;

import com.bah.tract.client.Main;
import com.sun.xml.wss.impl.callback.KeyStoreCallback;
import com.sun.xml.wss.impl.callback.PrivateKeyCallback;

/**
 * Allows Metro web service clients to programmatically select the client
 * certificate to use for web service authentication.
 */
public class CertStoreCallbackImpl implements
		javax.security.auth.callback.CallbackHandler,
		com.sun.xml.wss.AliasSelector {

	/**
	 * @see javax.security.auth.callback.CallbackHandler#handle(javax.security.auth.callback.Callback[]
	 *      callbacks)
	 */
	@Override
	public final void handle(final Callback[] callbacks) throws IOException,
			UnsupportedCallbackException {
		for (final Callback callback : callbacks) {
			if (callback instanceof KeyStoreCallback) {
				final KeyStoreCallback keyStoreCallback = (KeyStoreCallback) callback;
				keyStoreCallback.setKeystore(WindowsKeystore.getKeystore());
			} else if (callback instanceof PrivateKeyCallback) {
				final PrivateKeyCallback privateKeyCallback = (PrivateKeyCallback) callback;
				try {
					final PrivateKey key = (PrivateKey) WindowsKeystore
							.getKeystore().getKey(
									privateKeyCallback.getAlias(), null);
					privateKeyCallback.setKey(key);
				} catch (final UnrecoverableKeyException e) {
					throw new IOException(e);
				} catch (final KeyStoreException e) {
					throw new IOException(e);
				} catch (final NoSuchAlgorithmException e) {
					throw new IOException(e);
				}
			}
		}
	}

	/**
	 * @param map
	 *            ignored
	 * @return The alias associated with this callback if set. null if the alias
	 *         has not been set.
	 */
	@Override
	public final String select(@SuppressWarnings("rawtypes") final Map map) {
		return Preferences.userNodeForPackage(Main.class).get("certificate",
				null);
	}

}
